/**
 * WTF Engine
 *
 * License... etc.
 **
 * Render Module
 *
 * Provides:
 *	- Modelview matrix transforms
 *	- render routine
 *  - bindings to important OpenGL calls
 **
 * Authors: Sean Micklethwaite
 **/


#ifndef __renderH__
#define __renderH__

#include "game.h"
#include "graphics.h"
#include "graphicsdata.h"
#include "wtftypes.h"
#include "vector.h"
#include "2d.h"
#include "3d.h"
#include "camera.h"
#include <GL/glext.h>
#include "shader.h"
#include "texture.h"
#include <algorithm>
#include <Ogre.h>


namespace WtfEngine
{
	/**
	 * Renderable interface
	 * Denotes objects that can be renderered, such that they
	 * can be added to the Renderer's object list
	 **/
	class IRenderable : public virtual IGcObject {
		public:
			virtual void Render() = 0;
			
			GC_INTERFACE(IRenderable);
	};
	
	/// An object that can be displayed
	class Renderable : public GameObject, public virtual IRenderable
	{
		WtfGraphics::GraphicsData::tCacheRef mrGraphicsData;

	public:
		typedef GcReference<Renderable>	tRef;

		Renderable(const tCreationOptions& args, const WtfGraphics::GraphicsData::tCacheRef& d);
		virtual ~Renderable() {};

		virtual void Render() {
			mrGraphicsData->render();
		};

		WtfGraphics::GraphicsData::tCacheRef getGraphicsData() const {
			return mrGraphicsData;
		};

		void setGraphicsData(const WtfGraphics::GraphicsData::tCacheRef& r) {
			mrGraphicsData = r;
		};
		
		virtual void Destroy();

		virtual unsigned CalculateSerializedSize();
		virtual unsigned Serialize(void * pBuf);
		virtual unsigned Deserialize(void * pBuf);
	};
	

	/**
	 * The renderer
	 **/
	class Renderer : public Task<Renderer>, public Loggable<Renderer>
	{
	public:	
		typedef ObjectList<IRenderable::tRef>	tRenderList;
		typedef std::vector<IRenderable::tRef>	tOverlayStack;

		typedef enum {
			RENDER_OVERLAYS_ONLY,
			RENDER_WORLD,
			RENDER_WORLD_WIREFRAME,
			RENDER_PHYSICS
		} tRenderType;

	private:
		tRenderType				mRenderType;

		tRenderList				mRenderList;
		
		Ogre::Root * mpRoot;
		Ogre::RenderWindow * mpRenderWindow;
		Ogre::SceneManager * mpScene;
		Ogre::Camera * mpOgreCamera;
		Ogre::Viewport * mpViewport;

		IScreen::tRef mrScreen;
		ICamera::tRef mrCamera;

	public:
		Renderer(WtfGraphics::tScreenRef& screen);
		~Renderer();

		/// Calls render on all renderable objects
		void RenderAll();

		/// Renders the view of the scene from the specified camera, to
		/// the specified screen surface
		void Render(const IScreen::tRef& rScreen, const IPerspective::tRef& rCamera, tRenderType type = RENDER_WORLD);

		inline void PushObject(const IRenderable::tRef& rObj) {
			
		};

		inline void RemoveObject(const IRenderable::tRef& rObj) {
			
		};
		
		inline void PushOverlay(const IRenderable::tRef& rOverlay) {
			
		};

		inline void RemoveOverlay(const IRenderable::tRef& rOverlay) {
			
		};

		inline bool HasOverlay(const IRenderable::tRef& rOverlay) {
			
		};
		
		inline void SetCamera(const ICamera::tRef& cam){
			mrCamera = cam;
		};
		inline ICamera* GetCamera(){
			return &*mrCamera;
		};

		IScreen::tRef GetScreen(){
			return mrScreen;
		};

	protected:
		void Run();
		void OnPause();
		void OnResume();
		void OnWait();
	};
};

#endif
